package com.simple.manager.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.simple.annotation.Instance;
import com.simple.annotation.Observer;
import com.simple.core.impl.EnhanceSender;
import com.simple.manager.AbsManager;
import net.sf.cglib.proxy.Enhancer;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 此类以单例模式运行，不被容器管理，它是框架的核心组件之一
 */
public class InstanceManager extends AbsManager<String, Object> {

    private static InstanceManager instanceManager = new InstanceManager();

    private InstanceManager() {

    }

    public static InstanceManager getInstance() {
        if (Objects.isNull(instanceManager)) {
            instanceManager = new InstanceManager();
        }
        return instanceManager;
    }

    /**
     * 通过类名，执行注册操作
     *
     * @param clazz 被注册的类
     */
    public void register(Class<?> clazz) {
        if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) {
            return;
        }
        Instance instance = clazz.getDeclaredAnnotation(Instance.class);
        String key = instance.value();
        Object obj = createInstance(clazz);
        if (StrUtil.isEmpty(key)) {
            key = clazz.getName();
        }
        if (containsKey(key)) {
            throw new IllegalStateException(String.format("已经存在的key：%s", key));
        }
        register(key, obj);
    }

    private Object createInstance(Class<?> clazz) {
        Method[] methods = ReflectUtil.getMethods(clazz);
        List<Method> list = Arrays.stream(methods)
                .filter(method -> Objects.nonNull(method.getDeclaredAnnotation(Observer.class)))
                .collect(Collectors.toList());
        Object object = ReflectUtil.newInstance(clazz);
        if (CollUtil.isEmpty(list)) {
            return object;
        }
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(new EnhanceSender(list));
        return enhancer.create();
    }
}
